package com.atom.module.author.service.impl;


import com.atom.module.author.exception.UserPasswordNotMatchException;
import com.atom.module.author.exception.UserPasswordRetryLimitExceedException;
import com.atom.module.author.pojo.entity.Author;
import com.atom.module.author.utils.SecurityUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class PasswordService {

    public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";

    @Value(value = "${user.password.maxRetryCount}")
    private int maxRetryCount = 5;

    @Value(value = "${user.password.lockTime}")
    private int lockTime = 5 * 60 * 1000;

    private final Map<String, MutablePair<Integer, Long>> cache = new HashMap<>();

    /**
     * 登录账户密码错误次数缓存键名
     *
     * @return 缓存键key
     */
    public void validate(Author user) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();

        String key = PWD_ERR_CNT_KEY + username;
        MutablePair<Integer, Long> pair = cache.get(key);

        if (pair == null) {
            pair = new MutablePair<>(0, System.currentTimeMillis());
            cache.put(key, pair);
        }

        if (System.currentTimeMillis() - pair.right > lockTime) {
            pair = new MutablePair<>(0, System.currentTimeMillis());
            cache.put(key, pair);
        }

        if (pair.left >= maxRetryCount) {
            throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
        }

        if (!matches(user, password)) {
            pair.left += 1;
            pair.right = System.currentTimeMillis();
            throw new UserPasswordNotMatchException();
        } else {
            clearLoginRecordCache(username);
        }
    }

    public boolean matches(Author user, String rawPassword) {
        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
    }

    public void clearLoginRecordCache(String loginName) {
        cache.remove(PWD_ERR_CNT_KEY + loginName);
    }
}
